home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_n_z.arj / WILD.ASM < prev    next >
Assembly Source File  |  1988-03-16  |  38KB  |  853 lines

  1. ; WILD Public Domain 1988 by Charles Lazo III, v1.0
  2.  
  3. ; WILD.ASM    This program is used to run any other program (or DOS command)
  4. ;        by expanding program wild card parameters given on the command
  5. ;        line.  E.g., WILD PROG *.* would run a program, say PROG.EXE,
  6. ;        multiple times and supply it each time with a file from the
  7. ;        current directory matching *.* (i.e., every file in the current
  8. ;        directory would be supplied to PROG for execution).
  9.  
  10. rt        equ    0dh
  11. lf        equ    0ah
  12. of        equ    offset
  13. bptr        equ    byte ptr
  14. wp        equ    word ptr
  15.  
  16. code        segment
  17.         assume    cs:code, ds:code
  18.  
  19.         org    2ch
  20. env_seg        dw    ?        ; pointer to segment of our environment
  21.  
  22.         org    100h
  23. begin:        jmp    start
  24.  
  25. ;-------------------------------------------------------------------------------
  26. ; The wild card specification is placed here at the bottom of our stack to avoid
  27. ; having to specially set aside space for it.  It is used by the find_first
  28. ; routine to find the first file in the current directory meeting the wild card
  29. ; specification using the DOS Find First function.
  30. ;-------------------------------------------------------------------------------
  31. wild_spec    db    16 dup('STACK   ')    ; 128 bytes for stack
  32. our_stack    label    word
  33.  
  34. ss_save        dw    ?    ; place to store ss:sp
  35. sp_save        dw    ?
  36.  
  37. memory_used    dw    ?    ; keep track of memory paragraphs used
  38. env_size    dw    ?    ; number of bytes in the environment stored here
  39. cspc_addr    label    dword
  40.         dw    2 dup(?); store address of comspec variable here
  41. left_blank    dw    ?    ; stores pointer to start of wild card spec
  42. right_blank    dw    ?    ; stores pointer to end of wild card spec
  43. copy_size    dw    ?    ; stores size of command on command line (WILD)
  44. buffer_ptr    dw    0    ; pointer to buffer for list of filenames
  45.  
  46. switches    db    0        ; record presence of QUERY & NOEXT here
  47. file_attr    dw    0        ; store file attributes for file find
  48.  
  49. cmd_line    db    128 dup(0)    ; save original command line here
  50.  
  51. cmdl        db    ?,'/c',128 dup(?)    ; command line for EXEC
  52.  
  53. ;-------------------------------------------------------------------------------
  54. ; The parameter table to be passed to the DOS EXEC function:
  55. ;-------------------------------------------------------------------------------
  56. params        dw    ?    ; segment of environment block stored here
  57.         dw    of cmdl    ; offset of command line for program EXECed
  58.         dw    ?    ; segment of command line for program EXECed
  59.         dw    55h    ; offset of first FCB
  60.         dw    ?    ; segment of first FCB
  61.         dw    65h    ; offset of second FCB
  62.         dw    ?    ; segment of second FCB
  63.  
  64. ;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  65. ; The following routines (up to the label buffer:) operate under the assumption
  66. ; that both ds and es are set to the code segment of WILD.
  67. ;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  68.  
  69. ;-------------------------------------------------------------------------------
  70. ; When the WILD environment variable has NOEXT in its assignment string, then
  71. ; filename extensions are ignored (not supplied) when commands are passed to
  72. ; the DOS EXEC function.  This routine will remove any extension from the file-
  73. ; name in the DTA placed there by the DOS Find First and Continue File Search
  74. ; functions if NOEXT was found in the WILD environment variable.  The extension
  75. ; is removed by replacing the period separating the main part from the extension
  76. ; with a null.  Note that if a period is the only part of the filename, then it
  77. ; must be the dot representing the current directory so it is not removed.
  78. ;-------------------------------------------------------------------------------
  79.  
  80. remove_ext?    proc    near        ; removes any extension from filename
  81.         test    switches,noe    ; is WILD NOEXT env variable set?
  82.         jz    no_remove    ; no, don't remove extension
  83.         xor    al,al        ; find null terminating filename
  84.         mov    cx,14        ; max number of characters in ASCIIZ+1
  85.         cld            ; (for maintenance and documentation)
  86.         repne    scasb        ; search for null
  87.         sub    di,9eh        ; compute number of filename characters
  88.         mov    cx,di        ; and place it in cx for next search
  89.         mov    al,'.'        ; search for period prior to extension
  90.         mov    di,9eh        ; offset of filename in DTA
  91.         repne    scasb        ; search for period
  92.         jcxz    no_remove    ; can't remove extension if not there
  93.         cmp    di,9fh        ; if the period was the ONLY character,
  94.         jz    no_remove    ;   then it is the current directory
  95.         mov    bptr [di-1],0    ; set it to null to remove the extension
  96. no_remove:    ret
  97. remove_ext?    endp
  98.  
  99. ;-------------------------------------------------------------------------------
  100. ; find_size computes the length of a filename in the DTA placed there by the DOS
  101. ; find first and continue file search functions.  The length of the filename is
  102. ; returned in cx (the null character at the end of the ASCIIZ string is included
  103. ; in the count).  This routine is similar to file_size, qv.
  104. ;-------------------------------------------------------------------------------
  105.  
  106. find_size    proc    near        ; find size of filename (returned in cx)
  107.         call    remove_ext?    ; eliminate filename extension?
  108.         xor    al,al        ; find null at end of ASCIIZ filename
  109.         mov    di,9eh        ; offset of filename in DTA
  110.         mov    cx,14        ; max number of characters in ASCIIZ+1
  111.         cld            ; (for maintenance and documentation)
  112.         repne    scasb        ; search for null in ASCIIZ filename
  113.         sub    di,9eh        ; compute number of filename characters
  114.         mov    cx,di        ; return value in cx
  115.         ret
  116. find_size    endp
  117.  
  118. ;-------------------------------------------------------------------------------
  119. ; In this routine we check to see if there is enough memory presently allocated
  120. ; for the filename buffer to place another filename in the buffer.  First di is
  121. ; is set to the location in the buffer where the next filename will go.  If not
  122. ; enough memory has been allocated to allow the placement of another filename
  123. ; in the buffer, then more memory is allocated.  By using only the memory that
  124. ; is needed by the buffer (additional memory is allocated in blocks of 16 para-
  125. ; graphs or 256 bytes; an arbitrary value) the remaining memory can be used in
  126. ; the EXEC call.
  127. ;-------------------------------------------------------------------------------
  128.  
  129. set_di        proc    near        ; sets di to point to next available
  130.         mov    di,buffer_ptr    ;   location in filename buffer
  131.         push    cx        ; save filename size
  132.         or    di,di        ; is it zero (uninitialized)?
  133.         jz    init_di        ; yes, point it to start of buffer
  134.         mov    bx,di        ; use bx to find paragraphs used now
  135.         add    bx,0fh        ; round up to next paragraph
  136.         shr    bx,1        ; determine paragraph count
  137.         shr    bx,1
  138.         shr    bx,1
  139.         shr    bx,1
  140.         inc    bx        ; reserve one more than used
  141.         mov    ax,memory_used    ; memory paragraphs presently allocated
  142.         cmp    bx,ax        ; is memory to be used > allocated?
  143.         ja    get_more    ; yes, get more memory
  144. di_set:        pop    cx        ; restore filename size
  145.         ret
  146. get_more:    add    ax,16        ; ask for 256 more bytes (16 paragraphs)
  147.         mov    bx,ax        ; request sent in bx
  148.         mov    dx,ax        ; store in dx to assure request granted
  149.         mov    ah,4ah        ; DOS memory modify function (es is ok)
  150.         int    21h        ; ask DOS for it
  151.         cmp    bx,dx        ; DOS give what we wanted?
  152.         mov    dx,of mem_need    ; address error message in case not
  153.         jz    got_it        ; got requested memory
  154.         jmp    error_exit    ; nope, DOS don't have it, terminate
  155. init_di:    mov    di,of buffer
  156.         jmp    short di_set    ; exit with di at start of buffer
  157. got_it:        mov    memory_used,bx    ; update memory allocated
  158.         pop    cx        ; restore filename size
  159.         ret
  160. set_di        endp
  161.  
  162. ;-------------------------------------------------------------------------------
  163. ; With this call we copy the filename in the DTA (placed there by DOS Find First
  164. ; and Continue File Search functions) into the filename buffer.
  165. ;-------------------------------------------------------------------------------
  166.  
  167. store_filename    proc    near        ; store filename of file find in buffer
  168.         call    find_size    ; find size of filename in DTA (to cx)
  169.         call    set_di        ; set di to next location in buffer
  170.         mov    si,9eh        ; offset of filename in DTA
  171.         cld            ; (for maintenance and documentation)
  172.         rep    movsb        ; move ASCIIZ filename to buffer
  173.         mov    buffer_ptr,di    ; update buffer pointer
  174.         ret
  175. store_filename    endp
  176.  
  177. ;-------------------------------------------------------------------------------
  178. ; This one is similar to the find_size routine in that the size of a file is
  179. ; returned in cx.  While the find_size routine gets its input from the filename
  180. ; in the DTA, this one finds sizes of filenames set into the filename buffer.
  181. ; Additionally it differs in that find_size includes the terminal null in the
  182. ; count and this one does not.  Also the zero flag is set if no more filenames
  183. ; exist (else reset).
  184. ;-------------------------------------------------------------------------------
  185.  
  186. file_size    proc    near        ; size of next filename in buffer to cx
  187.         mov    di,buffer_ptr    ; get current buffer position
  188.         cmp    bptr [di],0    ; was the last the final filename?
  189.         jz    last_done    ; yes, return with zero flag set
  190.         mov    cx,di        ; save current buffer position
  191.         push    cx
  192.         mov    cx,14        ; longer than any ASCIIZ filename string
  193.         mov    al,0        ; search for null in ASCIIZ filename
  194.         cld            ; (for maintenance and documentation)
  195.         repne    scasb        ; find the null
  196.         mov    buffer_ptr,di    ; store new buffer position
  197.         pop    cx        ; recover last buffer position
  198.         sub    di,cx        ; compute size of filename in cx
  199.         xchg    cx,di
  200.         dec    cx        ; discard null and reset the zero flag
  201. last_done:    ret
  202. file_size    endp
  203.  
  204. ;-------------------------------------------------------------------------------
  205. ; A copy of the command line as given by the user (WILD's command line) is
  206. ; maintained at the location cmd_line.  The variables left_blank and right_blank
  207. ; point to the first and last characters of the wild card specification within
  208. ; cmd_line when this routine is called the first time or the first and last
  209. ; characters of the previous filename when the routine is called at succeeding
  210. ; times.  This blank is resized--either made larger or smaller--depending upon
  211. ; the size of the current filename that is to be copied into it.
  212. ;-------------------------------------------------------------------------------
  213.  
  214. resize_blank    proc    near        ; adjust filename blank to right size
  215.         mov    ax,left_blank    ; first character of blank
  216.         mov    bx,right_blank    ; last character of blank
  217.         sub    bx,ax        ; compute length of blank
  218.         inc    bx
  219.  
  220.         mov    di,right_blank    ; point to last character of blank
  221.         mov    al,rt        ; search for return character
  222.         push    cx        ; save filename size
  223.         mov    cx,127        ; larger than necessary, so ok
  224.         cld            ; (for maintenance and documentation)
  225.         repne    scasb        ; find the return character
  226.         dec    di        ; point di to return character
  227.         mov    cx,di        ; compute number to move in cx
  228.         mov    ax,right_blank
  229.         sub    cx,ax
  230.         pop    ax        ; get filename size
  231.  
  232.         cmp    ax,bx        ; greater, less than, or equal?
  233.         je    rb_done        ; finished if equal
  234.         jb    decrease    ; less than, so decrease blank
  235.         sub    ax,bx        ; compute amount filename is greater
  236.         mov    si,di        ; point si to return character
  237.         add    di,ax        ; di to new location of return character
  238.         std            ; decrement move this time
  239.         rep    movsb        ; make room for filename
  240.         mov    bx,right_blank    ; adjust this variable
  241.         add    bx,ax
  242.         mov    right_blank,bx
  243.         mov    bx,copy_size    ; and this one also
  244.         add    bx,ax
  245.         mov    copy_size,bx
  246.         mov    bl,cmd_line    ; and this one too
  247.         add    bl,al
  248.         mov    cmd_line,bl
  249. rb_done:    ret
  250.  
  251. decrease:    sub    bx,ax        ; compute amount blank is greater
  252.         mov    si,right_blank    ; point to first character after blank
  253.         inc    si
  254.         mov    di,si        ; compute new location for these chars
  255.         sub    di,bx
  256.         cld            ; (for maintenance and documentation)
  257.         rep    movsb        ; resize blank to filename size
  258.         mov    ax,right_blank    ; adjust this variable
  259.         sub    ax,bx
  260.         mov    right_blank,ax
  261.         mov    ax,copy_size    ; and this one also
  262.         sub    ax,bx
  263.         mov    copy_size,ax
  264.         mov    al,cmd_line    ; and this one too
  265.         sub    al,bl
  266.         mov    cmd_line,al
  267.         ret
  268. resize_blank    endp
  269.  
  270. ;-------------------------------------------------------------------------------
  271. ; cx contains filename size due to maintenance of this value on the stack while
  272. ; the resize_blank routine was called previous to the call to this one.  The
  273. ; routine copies a filename from the filename buffer into a holding area (the
  274. ; location in cmd_line called blank) prior to it's being copied to the command
  275. ; line used by EXEC.
  276. ;-------------------------------------------------------------------------------
  277.  
  278. copy_filename    proc    near        ; copy a buffer filename to cmd_line
  279.         mov    si,buffer_ptr    ; point si to current filename
  280.         sub    si,cx        ;   (since file_size updated buffer_ptr
  281.         dec    si        ;    we must go back for current file)
  282.         mov    di,left_blank    ; the place in cmd_line to copy to
  283.         cld            ; (for maintenance and documentation)
  284.         rep    movsb        ; filename --> cmd_line
  285.         ret
  286. copy_filename    endp
  287.  
  288. ;-------------------------------------------------------------------------------
  289. ; This routine prepares the next command line that will be passed to EXEC by
  290. ; using the next available filename from the filename buffer.  If all filenames
  291. ; have been processed, then the zero flag is set on return, else it is reset.
  292. ;-------------------------------------------------------------------------------
  293.  
  294. copy_command    proc    near        ; copy command to EXEC's command line
  295.         call    file_size    ; find size of filename (returned in cx)
  296.         jz    all_done    ; no more, so return with zero flag set
  297.         push    cx        ; save filename size
  298.         call    resize_blank    ; adjust filename blank to right size
  299.         pop    cx        ; restore filesize for copy_filename
  300.         call    copy_filename    ; filename from buffer --> command line
  301.  
  302.         mov    cx,copy_size    ; get size of command line copy
  303.         mov    al,cmd_line    ; set size of EXEC's command line
  304.         add    al,2        ;   account for increase due to "/c"
  305.         mov    cmdl,al        ;   set in size for EXEC
  306.         mov    si,of cmd_line+1; copy command to be executed
  307.         mov    di,of cmdl+3    ;   to proper location for EXEC
  308.         cld            ; (for maintenance and documentation)
  309.         rep    movsb        ; do the copy
  310.         or    al,al        ; al is nonzero so zero flag is reset
  311. all_done:    ret
  312. copy_command    endp
  313.  
  314. ;-------------------------------------------------------------------------------
  315. ; If the WILD environment variable contains the QUERY option, then this routine
  316. ; prompts the user with "(Y/N/A)?" for Yes, No, or Abort.  The zero flag is set
  317. ; on return if the user replies No, it is reset if the reply is Yes, and the
  318. ; carry flag is set if Abort is the reply (carry flag reset if Y or N).  These
  319. ; flag settings are preserved by the calling routine, wild_prompt, so that the
  320. ; code that calls wild_prompt can test them.  This code responds as if a Yes
  321. ; response were given if QUERY is not active.
  322. ;-------------------------------------------------------------------------------
  323.  
  324. wild_query?    proc    near        ; inquire Yes, No, or Abort if QUERY set
  325.         test    switches,que    ; is QUERY set in switches variable?
  326.         jz    wq_yes        ; no, return to caller as if Yes
  327.         mov    dx,of wq_prompt    ; prompt to send to standard error
  328.         mov    cx,wqp_size    ; number of characters to send
  329.         mov    bx,2        ; write to file handle 2 (std error)
  330.         mov    ah,40h        ; with DOS function 40h
  331.         int    21h
  332. wq_next:    mov    ah,7        ; DOS keyboard input without echo
  333.         int    21h
  334.         or    al,al        ; an ASCII character?
  335.         jnz    wq_ascii    ; yes, process the response
  336.         mov    ah,7        ; no, get and discard auxiliary byte
  337.         int    21h
  338.         jmp    short wq_next    ; continue input
  339. wq_ascii:    and    al,0dfh        ; capitalize
  340.         mov    response,al    ; and store it for (possible) output
  341.         cmp    al,'Y'        ; a Yes response?
  342.         je    wq_yes        ; uhuh, reset zero flag and exit
  343.         cmp    al,'N'        ; a No response?
  344.         je    wq_no        ; yeah, just exit (ZF is set)
  345.         cmp    al,'A'        ; an Abort response?
  346.         je    wq_abort    ; yep, set carry flag and exit
  347.         jmp    short wq_next    ; none of the above; try again
  348. wq_yes:        or    al,al        ; reset zero flag to indicate Yes
  349. wq_no:        pushf            ; save flags
  350.         mov    dx,of response    ; write this
  351.         mov    cx,1        ; one character
  352.         mov    bx,2        ; to standard error
  353.         mov    ah,40h        ; with DOS function 40h
  354.         int    21h
  355.         popf            ; recover return flags
  356.         ret
  357. wq_abort:    or    al,al        ; reset zero flag so not taken as No
  358.         stc            ; set carry flag to indicate abort
  359.         jmp    short wq_no    ; write response to screen
  360. wq_prompt    db    ' (Y/N/A)? '    ; prompt user with <(Yes, No, Abort)?>
  361. wqp_size    equ    $-wq_prompt    ; size of prompt
  362. response    db    ?        ; place to store user response to query
  363. wild_query?    endp
  364.  
  365. ;-------------------------------------------------------------------------------
  366. ; Here we show the user the command that will be executed next by WILD and if
  367. ; the WILD environment variable contains the QUERY option, then we will prompt
  368. ; (Y/N/A)? also.
  369. ;-------------------------------------------------------------------------------
  370.  
  371. wild_prompt    proc    near        ; output to std out the command EXECed
  372.         mov    dx,of wild_pmt    ; display "WILD>" lead in
  373.         mov    cx,wildpmt_size    ; size of lead in
  374.         mov    bx,2        ; write to file handle 2 (std error)
  375.         mov    ah,40h        ; with DOS function 40h
  376.         int    21h
  377.         mov    dx,of cmdl+3    ; point to command to be EXECed
  378.         mov    cx,copy_size    ; number of bytes to send to std out
  379.         dec    cx        ; but not the return at end of line
  380.         mov    bx,2        ; write to file handle 2 (std error)
  381.         mov    ah,40h        ; with DOS function 40h
  382.         int    21h
  383.         call    wild_query?    ; send a query?
  384.         pushf            ; save response
  385.         mov    dx,of wild_rtlf    ; return/linefeed to std out
  386.         mov    cx,2        ; just 2 characters to send
  387.         mov    bx,2        ; write to file handle 2 (std error)
  388.         mov    ah,40h        ; with DOS function 40h
  389.         int    21h
  390.         popf            ; restore response
  391.         ret
  392. wild_pmt    db    rt,lf,'WILD>'    ; lead in for WILD
  393. wildpmt_size    equ    $-wild_pmt
  394. wild_rtlf    db    rt,lf        ; newline after "prompt"
  395. wild_prompt    endp
  396.  
  397. find_rest:    call    store_filename    ; store filename as ASCIIZ in buffer
  398.         mov    ah,4fh        ; DOS continue file search function
  399.         int    21h
  400.         or    ax,ax        ; return code nonzero?
  401.         jnz    all_found    ; yes, all files have been found
  402.         jmp    short find_rest    ; continue file find
  403.  
  404. all_found:    mov    di,buffer_ptr    ; get file buffer pointer
  405.         mov    bptr [di],0    ; double null indicates end of buffer
  406.         mov    di,of buffer    ; start now at beginning of buffer
  407.         mov    buffer_ptr,di    ;   to process filenames
  408. next_file:    call    copy_command    ; copy command with filename to EXEC's
  409.                     ;   copy of the command line
  410.         jz    exit        ; zero flag set indicates completion
  411.         call    wild_prompt    ; command to screen and maybe prompt
  412.         jz    next_file    ; user said no to this one
  413.         jc    exit        ; user wants to abort
  414.         mov    ss_save,ss    ; save stack to restore upon return from
  415.         mov    sp_save,sp    ;   the EXEC
  416.  
  417.         lds    dx,cspc_addr    ; ds:dx points to name of prog to EXEC
  418.         mov    bx,of params    ; es:bx points to parameter block
  419.         mov    ax,4b00h    ; execute program after loading it
  420.         int    21h
  421.  
  422.         mov    ss,cs:ss_save    ; restore our stack
  423.         mov    sp,cs:sp_save
  424.  
  425.         mov    ax,cs        ; cs --> ds, es
  426.         mov    ds,ax
  427.         mov    es,ax
  428.         jmp    short next_file
  429.  
  430. exit:        mov    ax,4c00h    ; terminate with error code 0
  431.         int    21h
  432.  
  433. buffer:        ; store list of ASCIIZ filenames here prior to processing
  434.  
  435. ;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  436. ; The following routines will be used before the buffer is used and not again
  437. ; after the buffer begins to fill with ASCIIZ filenames from the current
  438. ; directory.  Since memory is saved by overwriting them, that is why they are
  439. ; placed here.  Even though this code and data will be overwritten as the file-
  440. ; name buffer begins to fill with files, the memory saved for the program's use
  441. ; includes all memory where this code and data reside.  A filename buffer is
  442. ; used to store the names of files obtained from the current directory because
  443. ; after the EXEC function is used DOS somehow looses some of the information it
  444. ; needs for the performance of the Continue File Search function.
  445. ;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
  446.  
  447. ;-------------------------------------------------------------------------------
  448. ; We use this routine to check for the presence of a space, tab or the beginning
  449. ; of the command line in order to determine the location of the start of a wild
  450. ; card specification.
  451. ;-------------------------------------------------------------------------------
  452.  
  453. space_tab_left    proc    near        ; return with Z flag set if di points to
  454.         cmp    bptr [di],' '    ;   a space
  455.         je    stl_z
  456.         cmp    bptr [di],9    ;   a tab
  457.         je    stl_z
  458.         cmp    di,of cmd_line    ;   or the start of the command line
  459.         je    stl_z
  460.         or    al,al        ; reset Z flag
  461. stl_z:        ret
  462. space_tab_left    endp
  463.  
  464. ;-------------------------------------------------------------------------------
  465. ; Checks for invalid filename characters following a wild card character to
  466. ; signal the end of the wild card spec.  Thus the space character--although it
  467. ; is not included in my PC DOS 3.20 manual as an invalid character (oversight?)
  468. ; --is included among them.  Also the period, even though it is an invalid
  469. ; filename character is not included among those checked since it is valid as a
  470. ; character in a wild card specification (same with * and ?).
  471. ;-------------------------------------------------------------------------------
  472.  
  473. check_invalid    proc    near        ; return with Z flag set if di points to
  474.         mov    ah,[di]        ;   an invalid filename character
  475.         push    ax        ; save wild card test character
  476.         cmp    ah,' '        ; space or less than?
  477.         jbe    ci_z        ; yes, return with zero flag set
  478.         mov    si,of inv_chars    ; point to set of invalid characters
  479.         cld            ; (for maintenance and documentation)
  480. get_inv:    lodsb            ; get one of these
  481.         or    al,al        ; end of invalid character set?
  482.         jz    ci_nz        ; yes, return with zero flag reset
  483.         cmp    ah,al        ; an invalid character
  484.         je    ci_z        ; yes, return with zero flag set
  485.         jmp    short get_inv    ; test another
  486. ci_z:        pop    ax        ; restore wild card test character
  487.         xor    ah,ah        ; set zero flag
  488.         ret            ; return (zero flag is set)
  489. ci_nz:        pop    ax        ; restore wild card test character
  490.         or    al,al        ; reset zero flag
  491.         ret
  492. inv_chars    db    '"/\[]:|< >+=;,',0    ; invalid filename characters
  493. check_invalid    endp
  494.  
  495. ;-------------------------------------------------------------------------------
  496. ; This routine will find the wild card specification in the copy of the command
  497. ; line (cmd_line), execute the DOS find first function, place the filename
  498. ; obtained from this function into the command line copy (cmd_line), copy this
  499. ; command into the command line that will be passed to EXEC, and then return.
  500. ; The location of the wild card spec in cmd_line is referred to by the term
  501. ; "blank", since this is a "fill in the blank" operation.
  502. ;-------------------------------------------------------------------------------
  503.         
  504. find_first    proc    near        ; find first file of wild card spec
  505.         mov    al,rt        ; search the end of command line first
  506.         mov    di,81h        ; start at first character
  507.         mov    cx,127        ; maximum is fewer, but this will do
  508.         cld            ; (for maintenance and documentation)
  509.         repne    scasb        ; find return character
  510.         sub    di,81h        ; compute number of characters to search
  511.         mov    copy_size,di    ; store here for later use
  512.  
  513.         mov    al,'*'        ; first test for presence of an asterisk
  514. search_wild:    mov    cx,copy_size    ; install number of characters to search
  515.         mov    di,of cmd_line+1; command line passed by DOS (copy)
  516.         cld            ; (for maintenance and documentation)
  517.         repne    scasb        ; do search
  518.         jcxz    not_this_wild    ; this wild card not found
  519.  
  520.         push    di        ; save position of char after wild card
  521.         dec    di        ; move to wild card
  522. back_one:    dec    di        ; test character left
  523.         call    space_tab_left    ; check for space, tab or beginning
  524.         jnz    back_one    ; go back a character and look again
  525.         inc    di        ; point to first character in blank
  526.         mov    left_blank,di    ; store position as start of blank
  527.         pop    di        ; points to character after wild card
  528.         dec    di        ; undone by next instruction
  529. over_one:    inc    di        ; test one character right
  530.         call    check_invalid    ; check if an invalid filename character
  531.         jnz    over_one    ; go forward a character and look again
  532.         dec    di        ; point to last character in blank
  533.         mov    right_blank,di    ; store position as end of blank
  534.         mov    si,left_blank    ; address blank for copy
  535.         mov    cx,di        ; construct size of blank in cx
  536.         inc    cx
  537.         sub    cx,si
  538.         mov    di,of wild_spec    ; copy blank (wild spec) here
  539.         cld            ; (for maintenance and documentation)
  540.         rep    movsb        ; do the copy to work space
  541.         mov    bptr [di],0    ; make it an ASCIIZ string
  542.         mov    dx,of wild_spec    ; address with ds:dx for find first
  543.         mov    cx,file_attr    ; find files with these attributes
  544.         mov    ah,4eh        ; DOS find first function
  545.         int    21h
  546.         or    ax,ax        ; return code nonzero?
  547.         jnz    none_found    ; yes, no files were found, return
  548.         xor    ax,ax        ; return code is zero
  549. none_found:    ret
  550.  
  551. not_this_wild:    cmp    al,'?'        ; did we search for a "?" yet?
  552.         je    no_wild        ; yes, no other wild
  553.         mov    al,'?'        ; no, so search for it too
  554.         jmp    short search_wild
  555. no_wild:    mov    ax,255        ; return 255 if no wild card found
  556.         ret
  557. find_first    endp
  558.  
  559. cspc_str    db    'COMSPEC='    ; COMSPEC string to find in environment
  560. cspc_size    equ    $-cspc_str    ; size of "COMSPEC=" string
  561.  
  562. notice        db    rt,lf,'WILD v1.0  Public Domain 1988 by Charles Lazo '
  563.         db    'III, CIS userid 72210,17',rt,lf
  564. notice_size    equ    $-notice
  565.  
  566. bad_DOS        db    rt,lf,'WILD:  Requires DOS version 2 or above.',rt,lf,0
  567. mem_need    db    rt,lf,'WILD:  Not enough memory.',rt,lf,0
  568. no_comspec    db    rt,lf,"WILD:  Can't find COMSPEC in environment."
  569.         db    rt,lf,0
  570. none_wild    db    rt,lf,'WILD:  No wild card characters were found.'
  571.         db    rt,lf,0
  572. no_file        db    rt,lf,'WILD:  No files were found.',rt,lf,0
  573.  
  574. ;-------------------------------------------------------------------------------
  575. ; Execution is transferred here when an error has occured.  The code that has
  576. ; transferred control here will place in dx the offset of the error message that
  577. ; will be sent to standard error.  This error message must be terminated by a
  578. ; null.  The program then exits with error level set to 1.
  579. ;-------------------------------------------------------------------------------
  580.  
  581. error_exit:    mov    ax,cs        ; assure ds and es at cs
  582.         mov    ds,ax
  583.         mov    es,ax
  584.         mov    di,dx        ; find the null terminating error string
  585.         xor    al,al        ; search for null
  586.         cld            ; (for maintenance and documentation)
  587.         mov    cx,0ffffh    ; largest possible
  588.         repne    scasb        ; find the null
  589.         mov    cx,di        ; compute number of characters to send
  590.         sub    cx,dx        ;   in cx
  591.         dec    cx
  592.         mov    bx,2        ; send them to standard error
  593.         mov    ah,40h        ; with DOS function 40h
  594.         int    21h
  595.         mov    ax,4c01h    ; exit with error code 1
  596.         int    21h
  597.  
  598. ;-------------------------------------------------------------------------------
  599. ; Execution comes here when the program begins.  First the DOS version is
  600. ; checked to be sure it is 2 or greater, then all memory is released except that
  601. ; which is needed to continue operation after the filename buffer begins to fill
  602. ; with filenames from the current directory.  (All code and data is retained,
  603. ; but that which lies beyond the label buffer: is overwritten by filenames as
  604. ; the filename buffer begins to fill.  If more memory is needed, then it is
  605. ; allocated by the set_di routine.)  The size of the environment is determined
  606. ; so that it can be used as a limit to the number of bytes to be searched for
  607. ; the two environment variables WILD and COMSPEC.  Next the string "WILD=" is
  608. ; searched for in the environment and if found, then the two data variables,
  609. ; switches and file_attr (defined at the top of this file), are initialized
  610. ; based upon the settings in this string.  Finally, the string "COMSPEC=" is
  611. ; searched for in the environment and if not found, the program sends a message
  612. ; to the screen and terminates with the error level set to 1.  If COMSPEC is
  613. ; found its segment and offset are stored in the variable cspc_addr to be used
  614. ; later to find the program (usually COMMAND.COM) that shall be used as a shell
  615. ; to run the command given by the user.
  616. ;-------------------------------------------------------------------------------
  617.  
  618. start:        mov    dx,of bad_DOS    ; prepare wrong version message
  619.         mov    ah,30h        ; get DOS version number
  620.         int    21h
  621.         cmp    al,2        ; DOS ver 2 or greater?
  622.         jae    DOS_ok        ; yes, good DOS version
  623.         jmp    short error_exit; else send error and exit
  624. DOS_ok:        mov    dx,of notice    ; show notice information
  625.         mov    cx,notice_size    ; length of notice message
  626.         mov    bx,2        ; send notice message to standard error
  627.         mov    ah,40h        ; with DOS function 40h
  628.         int    21h
  629.         mov    bx,of last    ; assure all code retained
  630.         mov    ax,of buffer    ; assure at least 256 bytes for buffer
  631.         add    ax,256
  632.         cmp    bx,ax        ; use the larger of these two
  633.         jae    bx_good        ; bx larger is good enough
  634.         mov    bx,ax        ; make bx good enough
  635. bx_good:    add    bx,0fh        ; round up to next paragraph
  636.         shr    bx,1        ; calculate paragraphs
  637.         shr    bx,1
  638.         shr    bx,1
  639.         shr    bx,1
  640.         mov    memory_used,bx    ; save here for later use
  641.         mov    ah,4ah        ; DOS modify block to reserve bx
  642.         int    21h        ;   paragraphs for code and buffer
  643.         mov    dx,memory_used    ; get number requested
  644.         cmp    bx,dx        ; is number available same as requested?
  645.         mov    dx,of mem_need    ; address memory needed error
  646.         jz    modify_ok    ; okay, on modify memory block
  647.         jmp    error_exit    ; error, not able to modify block
  648.  
  649. modify_ok:    mov    sp,of our_stack    ; move stack to memory owned by us
  650.         mov    si,80h        ; offset of command line given us by DOS
  651.         mov    di,of cmd_line    ; place to copy command line (it is
  652.         cld            ;   overwritten by DOS find file calls)
  653.         mov    cx,128        ; copy 128 bytes (DOS legal limit)
  654.         rep    movsb
  655.  
  656.         mov    ax,env_seg    ; get segment of environment
  657.         mov    params,ax    ; and place it in parameter table
  658.         mov    params+4,cs    ; segment of command line
  659.         mov    params+8,cs    ; segment of first FCB
  660.         mov    params+12,cs    ; segment of second FCB
  661.  
  662.         jmp    find_env_size    ; determine size of environment
  663.  
  664. ;-------------------------------------------------------------------------------
  665. ; This one searches the environment for the string pointed to by es:di.  The
  666. ; number of characters in the string is provided in dx, bx has the number of
  667. ; bytes to be searched and ds:si points to the starting point of the search.
  668. ; If the string is found, then the carry flag is reset to indicate success and
  669. ; the offset of the string into the segment of the environment is returned in
  670. ; si.  If the search fails, then the carry flag is set prior to return.
  671. ;-------------------------------------------------------------------------------
  672.  
  673. search_str    proc    near        ; search environment for string at di
  674.         mov    cx,bx        ; set number of bytes to search
  675. next_byte:    push    cx        ; save number of bytes to search
  676.         push    si        ; save start positions
  677.         push    di
  678.         mov    cx,dx        ; number of characters in string at di
  679.         cld            ; (for maintenance and documentation)
  680.         repe    cmpsb        ; compare the two strings
  681.         jcxz    str_found    ; found string at di in the environment
  682.         pop    di        ; get 'em back
  683.         pop    si
  684.         inc    si        ; bump pointer
  685.         pop    cx        ; get count
  686.         loop    next_byte
  687.         stc            ; set carry; string at di not found
  688.         ret
  689. str_found:    pop    di        ; remove stacked registers
  690.         pop    si
  691.         pop    cx
  692.         clc            ; clear carry; string at di found
  693.         ret
  694. search_str    endp
  695.  
  696. ;-------------------------------------------------------------------------------
  697. ; Here we search for the meaningful values that may be contained in the WILD
  698. ; environment variable.  These values are QUERY, NOEXT, H, S, and D (capital-
  699. ; ization is not significant).  The file WILD.DOC gives a description of the
  700. ; meaning of each.  First the whole string is capitalized and then a search is
  701. ; made for QUERY and for NOEXT.  The first and/or second bit of the byte
  702. ; switches is set depending upon the success of these searches.  Then H(idden),
  703. ; S(ystem) and D(irectory) values are searched and if found, then corresponding
  704. ; bits are set in the file_attr variable.  Also data for this and related code
  705. ; is defined at the end of this routine.
  706. ;-------------------------------------------------------------------------------
  707.  
  708. wild_settings    proc    near        ; set switches variable by WILD= string
  709.         mov    cs:ws_start,si    ; save offset of WILD variable setting
  710.         xor    bx,bx        ; count here the number of characters
  711.         cld            ; (for documentation and maintenance)
  712. ws_next:    lodsb
  713.         or    al,al        ; is it the null at end of ASCIIZ?
  714.         jz    ws_search    ; yes, capitalization is done
  715.         inc    bx        ; count it
  716.         cmp    al,'a'        ; is it below an 'a'?
  717.         jb    ws_next        ; yes, continue
  718.         cmp    al,'z'        ; is it above a 'z'?
  719.         ja    ws_next        ; yes, continue
  720.         and    bptr [si-1],0dfh; capitalize it
  721.         jmp    short ws_next    ; continue
  722. ws_search:    mov    si,cs:ws_start    ; get start of WILD variables
  723.         mov    di,of query    ; search for QUERY
  724.         mov    dx,query_size    ; size of query string
  725.         call    search_str    ; do the search
  726.         jc    do_noext    ; QUERY not found; look for NOEXT
  727.         or    cs:switches,que    ; set bit 0 to indicate QUERY found
  728. do_noext:    mov    si,cs:ws_start    ; get start of WILD variables
  729.         mov    di,of noext    ; search for NOEXT
  730.         mov    dx,noext_size    ; size of query string
  731.         call    search_str    ; do the search
  732.         jc    do_hidden    ; no NOEXT; look for hidden switch
  733.         or    cs:switches,noe    ; set bit 1 to indicate NOEXT found
  734. do_hidden:    mov    si,cs:ws_start    ; get start of WILD variables
  735.         mov    di,of hidden    ; search for hidden string
  736.         mov    dx,hidden_size    ; size of hidden string
  737.         call    search_str    ; do the search
  738.         jc    do_system    ; no hidden; look for system switch
  739.         or    cs:file_attr,hid; set bit 1 in file attribute
  740. do_system:    mov    si,cs:ws_start    ; get start of WILD variables
  741.         mov    di,of system    ; search for system string
  742.         mov    dx,system_size    ; size of system string
  743.         call    search_str    ; do the search
  744.         jc    do_direct    ; no system; look for direct switch
  745.         or    cs:file_attr,sys; set bit 2 in file attribute
  746. do_direct:    mov    si,cs:ws_start    ; get start of WILD variables
  747.         mov    di,of direct    ; search for direct string
  748.         mov    dx,direct_size    ; size of direct string
  749.         call    search_str    ; do the search
  750.         jc    ws_done        ; no direct; all done
  751.         or    cs:file_attr,dir; set bit 4 in file attribute
  752. ws_done:    ret
  753. ws_start    dw    ?        ; pointer to start of WILD env variables
  754. query        db    'QUERY'        ; string to find in WILD env variable
  755. query_size    equ    $-query
  756. noext        db    'NOEXT'        ; another string to find
  757. noext_size    equ    $-noext
  758. hidden        db    'H'        ; find this, then include hidden files
  759. hidden_size    equ    $-hidden
  760. system        db    'S'        ; find this, then include system files
  761. system_size    equ    $-system
  762. direct        db    'D'        ; find this, then directory files
  763. direct_size    equ    $-direct
  764. que        equ    1        ; set into switches if QUERY present
  765. noe        equ    2        ; set into switches if NOEXT present
  766. hid        equ    2        ; set into file_attr if hidden string
  767. sys        equ    4        ; set into file_attr if system string
  768. dir        equ    16        ; set into file_attr if direct string
  769. wild_settings    endp
  770.  
  771. ;-------------------------------------------------------------------------------
  772. ; Find the size of the environment so only this number of bytes will be searched
  773. ; for environment strings.
  774. ;-------------------------------------------------------------------------------
  775.  
  776. find_env_size:    mov    ax,env_seg    ; segment of environment --> es
  777.         mov    es,ax
  778.         xor    di,di        ; search begins at start of environment
  779.         xor    al,al        ; search for nulls in environment
  780.         mov    cx,8000h    ; environment is no larger than 32k
  781. next_word:    repne    scasb        ; find a null
  782.         scasb            ; a double null here?
  783.         jz    found_env_end    ; yes, signals end of environment block
  784.         jmp    short next_word    ; else continue searching
  785.  
  786. found_env_end:    mov    ax,8000h    ; number of bytes in environment --> cx
  787.         xchg    ax,cx
  788.         sub    cx,ax
  789.         mov    env_size,cx    ; store size of our environment
  790.  
  791. ;-------------------------------------------------------------------------------
  792. ; Setup segment registers for environment searches.
  793. ;-------------------------------------------------------------------------------
  794.         mov    ax,env_seg    ; segment of environment --> ds
  795.         mov    ds,ax
  796.         push    cs        ; cs --> es
  797.         pop    es
  798.         jmp    short wild_env    ; handle wild environment variables
  799.  
  800. ;-------------------------------------------------------------------------------
  801. ; First search for the string "WILD=" in the environment and if it is found,
  802. ; then set program switches depending upon what the WILD environment variable
  803. ; is set to.
  804. ;-------------------------------------------------------------------------------
  805. wild_str    db    'WILD='        ; WILD's environment variable string
  806. wild_size    equ    $-wild_str    ; size of "WILD=" string
  807.  
  808. wild_env:    xor    si,si        ; point to start of environment
  809.         mov    dx,wild_size    ; characters in string "WILD=" --> dx
  810.         mov    di,of wild_str    ; address WILD environment string
  811.         mov    bx,cs:env_size    ; number of bytes to search for string
  812.         call    search_str    ; find WILD string (if present)
  813.         jc    do_cspc        ; WILD string not found; do COMSPEC
  814.         add    si,wild_size    ; point si to value of WILD variable
  815.         call    wild_settings    ; record switch settings in environment
  816.  
  817. ;-------------------------------------------------------------------------------
  818. ; Now, search for "COMSPEC=" in the environment.  If it is found, then it will
  819. ; be used to provide the copy of COMMAND.COM to be used for the EXEC call(s).
  820. ; If it is not found, then we exit with an error message.
  821. ;-------------------------------------------------------------------------------
  822. do_cspc:    mov    bx,cs:env_size    ; number of bytes to search for COMSPEC
  823.         xor    si,si        ; point to start of environment
  824.         mov    dx,cspc_size    ; characters in string "COMSPEC=" --> dx
  825.         mov    di,of cspc_str    ; address COMSPEC string
  826.         call    search_str    ; find COMSPEC string (if present)
  827.         jnc    comspec_found    ; no carry, COMSPEC string was found
  828.  
  829.         mov    dx,of no_comspec; tell can't find COMSPEC, then exit
  830.         jmp    error_exit
  831.  
  832. comspec_found:    add    si,cspc_size        ; make si point to COMSPEC value
  833.         mov    wp cs:cspc_addr,si    ; store comspec offset
  834.         mov    wp cs:cspc_addr+2,ds    ; store comspec segment
  835.         push    cs        ; cs --> ds
  836.         pop    ds        ; (now cs, ds, and es are all same)
  837.         call    find_first    ; find the first file in the directory
  838.         cmp    ax,255        ; special return for no wild card found?
  839.         jne    wild_found    ; no, check if a file was found
  840.         mov    dx,of none_wild    ; send this message and end
  841.         jmp    error_exit
  842. wild_found:    or    ax,ax        ; a file found?
  843.         jnz    none_here    ; no, say so and end
  844.         jmp    find_rest    ; yes, find the remainder of files
  845. none_here:    mov    dx,of no_file    ; address no file message
  846.         jmp    error_exit
  847.  
  848. last:        ; offset of end of program.  Used to assure that all code is
  849.         ; retained with memory modify operation at the start of code.
  850.  
  851. code        ends
  852.         end    begin
  853.